﻿using System;
using System.Collections.Generic;

using RayDen.RayEngine;
using RayDen.RayEngine.Core;
using RayDen.RayEngine.Core.Interface;
using RayDen.RayEngine.Core.Types;

using RayEngine.Spectral.Engine.Integrators.PathTracer;

using Path = RayEngine.Spectral.Engine.Integrators.PathTracer.DeferredPathTracerSampler;
namespace RayEngine.Spectral.Engine
{
    public class PathBuffer : PathBufferBase<Path>
    {
        protected internal SceneManager SceneManager;

        public override void Init(int maxPaths, RayEngineScene scene, IImageFilm agg, SamplingContext sc)
        {
            this.maxPaths = maxPaths;
            this.Sampler = sc.PrimarySpaceSampler;
            this.Scene = scene;
            this.film = agg;
            this.sampleBuffer = film.GetFreeSampleBuffer();
            this.paths = new List<Path>(scene.MaxPaths + 1);
        }

        public override void ReInit()
        {
            for (var i = 0; i < paths.Count; ++i)
                paths[i].InitPath(this);
            firstPath = 0;
            //film.Reset();

            statsRenderingStart = DateTime.UtcNow.Ticks / 1000;
            statsTotalSampleCount = 0;
        }


        public override void FillRayBuffer(RayBuffer rayBuffer)
        {
            if (paths.Count == 0)
            {
                // Need at least 2 paths
                paths.Add(this.CreatePathSampler());
                paths.Add(this.CreatePathSampler());

                paths[0].InitPath(this);
                paths[1].InitPath(this);

                firstPath = 0;
            }

            bool allPathDone = true;
            lastPath = firstPath;
            for (; ; )
            {
                if (!paths[lastPath].FillRayBuffer(rayBuffer))
                {
                    // Not enough free space in the RayBuffer
                    allPathDone = false;
                    break;
                }

                lastPath = (lastPath + 1) % paths.Count;
                if (lastPath == firstPath)
                    break;
            }

            if (allPathDone)
            {
                var newPaths = 0;
                var maxNewPaths = maxPaths;

                for (; ; )
                {
                    newPaths++;
                    if (newPaths > maxNewPaths)
                    {
                        firstPath = 0;
                        lastPath = paths.Count - 1;
                        break;
                    }

                    var p = this.CreatePathSampler();
                    paths.Add(p);
                    p.InitPath(this);
                    if (!p.FillRayBuffer(rayBuffer))
                    {
                        firstPath = 0;
                        lastPath = paths.Count - 2;
                        break;
                    }
                }
            }
        }


        protected override Path CreatePathSampler()
        {
            var pr = new Path{ };
            pr.InitPath(this);
            return pr;
        }
    }
}
